﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using alib.Collections;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	[DebuggerTypeProxy(typeof(TfsSlotRef))]
	public struct ConstraintRef
	{
		[DebuggerStepThrough]
		public ConstraintRef(Tfs tfs, Edge host, int i_feat)
		{
			this.tfs = tfs;
			this.Host = host;
			this.i_feat = i_feat;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs tfs;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge Host;

		public void SetHostType(Type new_type)
		{
			if (HostType != new_type)
			{
				Host = tfs.tu.CreateEdge(new_type, Host.Mark, Host.IsCoreferenced);
				if (!HostType.HasFeature(i_feat))
					i_feat = -1;
			}
		}

		public Edge.Flag UnifyInConstraintType(Type t)
		{
			Debug.Assert(i_feat >= 0, "UnifyInType: Edge has no feature selected.");
			Type glb, t0 = ConstraintType;
			if ((glb = t0.IsTop ? t : t.tu.UnifyTypesFull(t0, t)) == null)
				return Edge.Flag.Bottom;

			if (glb != t0)
			{
				Edge old_edge, new_edge;
				tfs.TryGetEdge(i_feat, Host.Mark, out old_edge);
				new_edge = ((WriteableTfs)tfs).CreateEdge(glb, old_edge.IsCoreferenced);
				((WriteableTfs)tfs).SetEdge(i_feat, Host.Mark, new_edge);
			}
			return glb.EdgeFlag;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Type HostType { [DebuggerStepThrough] get { return tfs.tu.GetEdgeType(Host.FlagsId); } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int i_feat;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String Feature { [DebuggerStepThrough] get { return tfs.ftm[i_feat].feature; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public FeatMark FeatMark { [DebuggerStepThrough] get { return new FeatMark(i_feat, Host.Mark); } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Type ConstraintType { [DebuggerStepThrough] get { return tfs.tu.GetEdgeType(Constraint.FlagsId); } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge Constraint
		{
			[DebuggerStepThrough]
			get
			{
				Edge e;
				tfs.TryGetEdge(i_feat, Host.Mark, out e);
				return e;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public unsafe TfsSlot TfsSlot
		{
			[DebuggerStepThrough]
			get { return new TfsSlot(tfs, i_feat < 0 ? 0 : tfs.GetEdgeIndex(i_feat, Host.Mark, null)); }
		}

		public override String ToString()
		{
			if (Host.Mark == 0)
				return "(Host Mark==0)";
			if (i_feat < 0)
				return Host.Mark == 1 ? "[TOPMST]" : "(not valid)";

			return String.Format("{0} → {1}", Feature.ToUpper(), Constraint);
		}
	};
}
